package com.odata.mediawiki;

import org.joda.time.LocalDateTime;
import org.odata4j.core.*;
import org.odata4j.edm.*;
import org.odata4j.edm.EdmEntityContainer.Builder;
import org.odata4j.edm.EdmProperty.CollectionKind;
import org.odata4j.producer.*;
import org.odata4j.producer.edm.MetadataProducer;

import com.sun.nio.sctp.Association;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

/**
 * An ODataProducer implementation for creating an end point for Media Wiki website.
 * This producer has methods that allows us to create, update or delete entities.
 * This producer also allows us to retrieve the metadata, retrieve the entities, their navigation properties and
 * also invoking the functions and actions.
 * The producer interacts with the Media Wiki API using WikiEntityGetters to create/retrieve pages, categories etc.
 *
 * @author Aashish Salokhe
 * @author Kedar Deshpande
 * @since 1.0
 */
@Copyright
public class MediaWikiProducer implements ODataProducer {

	/**
	 * Domain name of Media Wiki site.
	 */
	private static String domain;

	/**
	 * Name of the Media Wiki site.
	 */
	private static String scriptPath;

	/**
	 * Returns the parameters set for this producer.
	 * @return A set of parameter values as strings.
	 */
	static String[] getParameter() {
		return new String[]{domain,scriptPath};
	}

	/**
	 * Sets the given parameters for this producer.
	 * @param domain Domain name of Media Wiki site.
	 * @param scriptPath Name of the Media Wiki site.
	 */
	static void setParameter(String domain, String scriptPath) {
		MediaWikiProducer.domain = domain;
		MediaWikiProducer.scriptPath = scriptPath;
	}

	/**
	 * Obtains the service metadata for this producer.
	 *
	 * @return a fully-constructed metadata object
	 */
	@Override
	public EdmDataServices getMetadata() {
		EdmDataServices.Builder edsBuilder = EdmDataServices.newBuilder();
		EdmSchema.Builder schemaBuilder = EdmSchema.newBuilder();
		EdmEntityContainer.Builder containerBuilder = EdmEntityContainer.newBuilder();
		EdmEntitySet.Builder esBuilder = EdmEntitySet.newBuilder();
		EdmEntityType.Builder etBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epTSBuilder = EdmProperty.newBuilder("timestamp");
		epTSBuilder.setNullable(true);
		epTSBuilder.setType(EdmSimpleType.DATETIME);

		EdmProperty.Builder epProBuilder = EdmProperty.newBuilder("protection");
		epProBuilder.setNullable(true);
		epProBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epDTBuilder = EdmProperty.newBuilder("displaytitle");
		epDTBuilder.setNullable(false);
		epDTBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epTokenBuilder = EdmProperty.newBuilder("token");
		epTokenBuilder.setNullable(true);
		epTokenBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epLPBuilder = EdmProperty.newBuilder("lastpurged");
		epLPBuilder.setNullable(true);
		epLPBuilder.setType(EdmSimpleType.DATETIME);

		EdmProperty.Builder epExistsBuilder = EdmProperty.newBuilder("exists");
		epExistsBuilder.setNullable(true);
		epExistsBuilder.setType(EdmSimpleType.BOOLEAN);

		EdmProperty.Builder epLRIBuilder = EdmProperty.newBuilder("lastrevid");
		epLRIBuilder.setNullable(true);
		epLRIBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epSZBuilder = EdmProperty.newBuilder("size");
		epSZBuilder.setNullable(true);
		epSZBuilder.setType(EdmSimpleType.INT32);

		EdmProperty.Builder epPCBuilder = EdmProperty.newBuilder("PageContent");
		epPCBuilder.setNullable(true);
		epPCBuilder.setType(EdmSimpleType.STRING);

		List<EdmProperty.Builder> propertyBuilderList = new ArrayList<EdmProperty.Builder>();
		propertyBuilderList.add(epSZBuilder);
		propertyBuilderList.add(epLRIBuilder);
		propertyBuilderList.add(epExistsBuilder);
		propertyBuilderList.add(epLPBuilder);
		propertyBuilderList.add(epTokenBuilder);
		propertyBuilderList.add(epTSBuilder);
		propertyBuilderList.add(epDTBuilder);
		propertyBuilderList.add(epProBuilder);
		propertyBuilderList.add(epPCBuilder);

		etBuilder.addKeys("displaytitle");
		etBuilder.addProperties(propertyBuilderList);
		etBuilder.setName("Page");
		etBuilder.setNamespace("ODataMediawiki");

		esBuilder.setName("Pages");
		esBuilder.setEntityTypeName("Page");
		esBuilder.setEntityType(etBuilder);

		/***************************************/
		EdmEntitySet.Builder esCatBuilder = EdmEntitySet.newBuilder();
		EdmEntityType.Builder etCatBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epCTBuilder = EdmProperty.newBuilder("CategoryTitle");
		epCTBuilder.setNullable(false);
		epCTBuilder.setType(EdmSimpleType.STRING);

		EdmNavigationProperty.Builder pagesNavProp = EdmNavigationProperty.newBuilder("Pages");
		EdmAssociation.Builder relationshipBuilder = EdmAssociation.newBuilder();
		relationshipBuilder.setNamespace("ODataMediawiki");
		EdmAssociationEnd.Builder end1 = EdmAssociationEnd.newBuilder();
		EdmAssociationEnd.Builder end2 = EdmAssociationEnd.newBuilder();
		end1.setRole("ODataMediawiki.Category");
		end1.setType(etCatBuilder);
		end1.setMultiplicity(EdmMultiplicity.MANY);
		end2.setMultiplicity(EdmMultiplicity.MANY);
		end2.setType(etBuilder);
		end2.setRole("ODataMediawiki.Page");
		relationshipBuilder.setName("HasPages");
		relationshipBuilder.setEnds(end1, end2);
		pagesNavProp.setFromTo(end1, end2);
		pagesNavProp.setRelationship(relationshipBuilder);

		etCatBuilder.addNavigationProperties(pagesNavProp);

		EdmNavigationProperty.Builder subCatNavProp = EdmNavigationProperty.newBuilder("SubCategories");
		EdmAssociation.Builder relationshipBuilderSubCat= EdmAssociation.newBuilder();
		relationshipBuilderSubCat.setNamespace("ODataMediawiki");
		EdmAssociationEnd.Builder endSC1 = EdmAssociationEnd.newBuilder();
		EdmAssociationEnd.Builder endSC2 = EdmAssociationEnd.newBuilder();
		endSC1.setRole("ODataMediawiki.Category");
		endSC1.setType(etCatBuilder);
		endSC1.setMultiplicity(EdmMultiplicity.ONE);
		endSC2.setMultiplicity(EdmMultiplicity.MANY);
		endSC2.setType(etCatBuilder);
		endSC2.setRole("ODataMediawiki.Category");

		relationshipBuilderSubCat.setName("HasSubCategories");
		relationshipBuilderSubCat.setEnds(endSC1, endSC2);
		subCatNavProp.setFromTo(endSC1, endSC2);

		subCatNavProp.setRelationship(relationshipBuilderSubCat);

		etCatBuilder.addNavigationProperties(subCatNavProp);

		List<EdmProperty.Builder> propertyCTBuilderList = new ArrayList<EdmProperty.Builder>();
		propertyCTBuilderList.add(epCTBuilder);

		etCatBuilder.addKeys("CategoryTitle");
		etCatBuilder.addProperties(propertyCTBuilderList);
		etCatBuilder.setName("Category");
		etCatBuilder.setNamespace("ODataMediawiki");

		esCatBuilder.setName("Categories");
		esCatBuilder.setEntityTypeName("Category");
		esCatBuilder.setEntityType(etCatBuilder);

		EdmEntitySet.Builder esPRBuilder = EdmEntitySet.newBuilder();
		EdmEntityType.Builder etPRBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epPRTSBuilder = EdmProperty.newBuilder("TimeStamp");
		epPRTSBuilder.setNullable(true);
		epPRTSBuilder.setType(EdmSimpleType.DATETIME);

		EdmProperty.Builder epSummryBuilder = EdmProperty.newBuilder("Summary");
		epSummryBuilder.setNullable(true);
		epSummryBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epUserBuilder = EdmProperty.newBuilder("User");
		epUserBuilder.setNullable(true);
		epUserBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epTitleBuilder = EdmProperty.newBuilder("Title");
		epTitleBuilder.setNullable(true);
		epTitleBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epIsNewBuilder = EdmProperty.newBuilder("IsNew");
		epIsNewBuilder.setNullable(true);
		epIsNewBuilder.setType(EdmSimpleType.BOOLEAN);

		EdmProperty.Builder epIsBotBuilder = EdmProperty.newBuilder("IsBot");
		epIsBotBuilder.setNullable(true);
		epIsBotBuilder.setType(EdmSimpleType.BOOLEAN);

		EdmProperty.Builder epIsMinorBuilder = EdmProperty.newBuilder("IsMinor");
		epIsMinorBuilder.setNullable(true);
		epIsMinorBuilder.setType(EdmSimpleType.BOOLEAN);

		EdmProperty.Builder epPRSZBuilder = EdmProperty.newBuilder("Size");
		epPRSZBuilder.setNullable(true);
		epPRSZBuilder.setType(EdmSimpleType.INT32);

		EdmProperty.Builder epRevIdBuilder = EdmProperty.newBuilder("RevisionId");
		epRevIdBuilder.setNullable(false);
		epRevIdBuilder.setType(EdmSimpleType.INT32);

		List<EdmProperty.Builder> propertyPRBuilderList = new ArrayList<EdmProperty.Builder>();
		propertyPRBuilderList.add(epPRTSBuilder);
		propertyPRBuilderList.add(epSummryBuilder);
		propertyPRBuilderList.add(epUserBuilder);
		propertyPRBuilderList.add(epTitleBuilder);
		propertyPRBuilderList.add(epIsNewBuilder);
		propertyPRBuilderList.add(epIsBotBuilder);
		propertyPRBuilderList.add(epIsMinorBuilder);
		propertyPRBuilderList.add(epPRSZBuilder);
		propertyPRBuilderList.add(epRevIdBuilder);

		etPRBuilder.addKeys("RevisionId");
		etPRBuilder.addProperties(propertyPRBuilderList);
		etPRBuilder.setName("PageRevision");
		etPRBuilder.setNamespace("ODataMediawiki");

		esPRBuilder.setName("PageRevisions");
		esPRBuilder.setEntityTypeName("PageRevision");
		esPRBuilder.setEntityType(etPRBuilder);

		EdmEntitySet.Builder esFileBuilder = EdmEntitySet.newBuilder();
		EdmEntityType.Builder etFileBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epFNBuilder = EdmProperty.newBuilder("FileName");
		epFNBuilder.setNullable(false);
		epFNBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epMDBuilder = EdmProperty.newBuilder("metadata");
		epMDBuilder.setNullable(true);
		epMDBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epMIMEBuilder = EdmProperty.newBuilder("mime");
		epMIMEBuilder.setNullable(true);
		epMIMEBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epFNSZBuilder = EdmProperty.newBuilder("size");
		epFNSZBuilder.setNullable(true);
		epFNSZBuilder.setType(EdmSimpleType.INT32);

		List<EdmProperty.Builder> propertyFNBuilderList = new ArrayList<EdmProperty.Builder>();
		propertyFNBuilderList.add(epFNBuilder);
		propertyFNBuilderList.add(epMDBuilder);
		propertyFNBuilderList.add(epMIMEBuilder);
		propertyFNBuilderList.add(epFNSZBuilder);

		etFileBuilder.addKeys("FileName");
		etFileBuilder.addProperties(propertyFNBuilderList);
		etFileBuilder.setName("File");
		etFileBuilder.setNamespace("ODataMediawiki");

		esFileBuilder.setName("Files");
		esFileBuilder.setEntityTypeName("File");
		esFileBuilder.setEntityType(etFileBuilder);

		EdmEntitySet.Builder esImageBuilder = EdmEntitySet.newBuilder();
		EdmEntityType.Builder etImageBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epINBuilder = EdmProperty.newBuilder("FileName");
		epINBuilder.setNullable(false);
		epINBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epIMDBuilder = EdmProperty.newBuilder("metadata");
		epIMDBuilder.setNullable(true);
		epIMDBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epIMIMEBuilder = EdmProperty.newBuilder("mime");
		epIMIMEBuilder.setNullable(true);
		epIMIMEBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epINSZBuilder = EdmProperty.newBuilder("size");
		epINSZBuilder.setNullable(true);
		epINSZBuilder.setType(EdmSimpleType.INT32);

		EdmProperty.Builder epHBuilder = EdmProperty.newBuilder("height");
		epHBuilder.setNullable(true);
		epHBuilder.setType(EdmSimpleType.INT32);

		EdmProperty.Builder epWBuilder = EdmProperty.newBuilder("width");
		epWBuilder.setNullable(true);
		epWBuilder.setType(EdmSimpleType.INT32);

		List<EdmProperty.Builder> propertyINBuilderList = new ArrayList<EdmProperty.Builder>();
		propertyINBuilderList.add(epINBuilder);
		propertyINBuilderList.add(epIMDBuilder);
		propertyINBuilderList.add(epIMIMEBuilder);
		propertyINBuilderList.add(epINSZBuilder);
		propertyINBuilderList.add(epHBuilder);
		propertyINBuilderList.add(epWBuilder);

		etImageBuilder.addKeys("FileName");
		etImageBuilder.addProperties(propertyINBuilderList);
		etImageBuilder.setName("Image");
		etImageBuilder.setNamespace("ODataMediawiki");

		esImageBuilder.setName("Images");
		esImageBuilder.setEntityTypeName("Image");
		esImageBuilder.setEntityType(etImageBuilder);

		EdmEntityType.Builder etSiteBuilder = EdmEntityType.newBuilder();

		EdmProperty.Builder epSNBuilder = EdmProperty.newBuilder("SiteName");
		epSNBuilder.setNullable(false);
		epSNBuilder.setType(EdmSimpleType.STRING);

		EdmProperty.Builder epInfoBuilder = EdmProperty.newBuilder("Info");
		epInfoBuilder.setNullable(true);
		epInfoBuilder.setType(EdmSimpleType.STRING);

		List<EdmProperty.Builder> propertySiteBuilderList = new ArrayList<EdmProperty.Builder>();
		propertySiteBuilderList.add(epSNBuilder);
		propertySiteBuilderList.add(epInfoBuilder);


		etSiteBuilder.addKeys("SiteName");
		etSiteBuilder.addProperties(propertySiteBuilderList);
		etSiteBuilder.setName("Site");
		etSiteBuilder.setNamespace("ODataMediawiki");

		EdmFunctionImport.Builder getAllLinksFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getAllLinksFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getAllLinksRT = EdmCollectionType.newBuilder();

		getAllLinksFP.setName("Page");
		getAllLinksFP.setNullable(false);
		getAllLinksFP.setType(etBuilder);
		getAllLinksFI.addParameters(getAllLinksFP);
		getAllLinksFI.setEntitySet(esBuilder);
		getAllLinksFI.setName("GetAllLinks");
		getAllLinksRT.setKind(CollectionKind.Collection);
		getAllLinksRT.setCollectionType(EdmSimpleType.newBuilder(EdmSimpleType.STRING));
		getAllLinksFI.setReturnType(getAllLinksRT);
		getAllLinksFI.setHttpMethod("get");

		EdmFunctionImport.Builder getLangFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getLangFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getLangRT = EdmCollectionType.newBuilder();

		EdmComplexType.Builder complexTypeBuilder = EdmComplexType.newBuilder();
		complexTypeBuilder.setName("KeyValuePair");
		complexTypeBuilder.setNamespace("ODataMediawiki");
		EdmProperty.Builder edmPropBuilder1 = EdmProperty.newBuilder(null);
		edmPropBuilder1.setType(EdmSimpleType.STRING);
		edmPropBuilder1.setName("Name");
		edmPropBuilder1.setNullable(false);
		EdmProperty.Builder edmPropBuilder2 = EdmProperty.newBuilder(null);
		edmPropBuilder2.setType(EdmSimpleType.STRING);
		edmPropBuilder2.setName("Value");
		edmPropBuilder2.setNullable(false);
		complexTypeBuilder.addProperties(edmPropBuilder1, edmPropBuilder2);

		getLangFP.setName("Page");
		getLangFP.setNullable(false);
		getLangFP.setType(etBuilder);
		getLangFI.addParameters(getLangFP);
		getLangFI.setEntitySet(esBuilder);
		getLangFI.setName("GetLangLinks");
		getLangRT.setKind(CollectionKind.Collection);
		getLangRT.setCollectionType(complexTypeBuilder);
		getLangFI.setReturnType(getLangRT);
		getLangFI.setHttpMethod("get");

		EdmFunctionImport.Builder getCatFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getCatFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getCatRT = EdmCollectionType.newBuilder();

		getCatFP.setName("Page");
		getCatFP.setNullable(false);
		getCatFP.setType(etBuilder);
		getCatFI.addParameters(getCatFP);
		getCatFI.setEntitySet(esBuilder);
		getCatFI.setName("GetCategories");
		getCatRT.setKind(CollectionKind.Collection);
		getCatRT.setCollectionType(EdmSimpleType.newBuilder(EdmSimpleType.STRING));
		getCatFI.setReturnType(getCatRT);
		getCatFI.setHttpMethod("get");

		EdmFunctionImport.Builder getImgFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getImgFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getImgRT = EdmCollectionType.newBuilder();

		getImgFP.setName("Page");
		getImgFP.setNullable(false);
		getImgFP.setType(etBuilder);
		getImgFI.addParameters(getImgFP);
		getImgFI.setEntitySet(esBuilder);
		getImgFI.setName("GetImages");
		getImgRT.setKind(CollectionKind.Collection);
		getImgRT.setCollectionType(EdmSimpleType.newBuilder(EdmSimpleType.STRING));
		getImgFI.setReturnType(getImgRT);
		getImgFI.setHttpMethod("get");

		EdmFunctionImport.Builder getL2HFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getL2HFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getL2HRT = EdmCollectionType.newBuilder();

		getL2HFP.setName("Page");
		getL2HFP.setNullable(false);
		getL2HFP.setType(etBuilder);
		getL2HFI.addParameters(getL2HFP);
		getL2HFI.setEntitySet(esBuilder);
		getL2HFI.setName("GetLinksToHere");
		getL2HRT.setKind(CollectionKind.Collection);
		getL2HRT.setCollectionType(EdmSimpleType.newBuilder(EdmSimpleType.STRING));
		getL2HFI.setReturnType(getL2HRT);
		getL2HFI.setHttpMethod("get");

		EdmFunctionImport.Builder getAllRevFI = EdmFunctionImport.newBuilder();
		EdmFunctionParameter.Builder getAllRevFP = EdmFunctionParameter.newBuilder();
		EdmCollectionType.Builder getAllRevRT = EdmCollectionType.newBuilder();

		getAllRevFP.setName("Page");
		getAllRevFP.setNullable(false);
		getAllRevFP.setType(etBuilder);
		getAllRevFI.addParameters(getAllRevFP);
		getAllRevFI.setEntitySet(esBuilder);
		getAllRevFI.setName("GetAllRevisions");
		getAllRevRT.setKind(CollectionKind.Collection);
		getAllRevRT.setCollectionType(EdmSimpleType.newBuilder(EdmSimpleType.STRING));
		getAllRevFI.setReturnType(getAllRevRT);
		getAllRevFI.setHttpMethod("get");

		try
		{
		containerBuilder.setName("Container");

		containerBuilder.addEntitySets(new EdmEntitySet.Builder[]{esBuilder,esCatBuilder,esPRBuilder,esFileBuilder,esImageBuilder});
		containerBuilder.addFunctionImports(new EdmFunctionImport.Builder[]{getAllLinksFI,getLangFI,getCatFI,getImgFI,getL2HFI,getAllRevFI});
		schemaBuilder.setNamespace("ODataMediawiki");
		schemaBuilder.addEntityContainers(containerBuilder);
		schemaBuilder.addEntityTypes(new EdmEntityType.Builder[]{etBuilder,etCatBuilder,etPRBuilder,etFileBuilder,etImageBuilder,etSiteBuilder});
		List<EdmAssociation.Builder> associationList = new ArrayList<EdmAssociation.Builder>();
		associationList.add(relationshipBuilder);
		associationList.add(relationshipBuilderSubCat);

		schemaBuilder.addAssociations(associationList);
		schemaBuilder.addComplexTypes(complexTypeBuilder);
		edsBuilder.addSchemas(schemaBuilder);
		return edsBuilder.build();
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;

	}

	@Override
	public MetadataProducer getMetadataProducer() {
		return null;
	}

	/**
	 * Gets all the entities for a given set matching the query information.
	 *
	 * @param entitySetName the entity-set name for entities to return
	 * @param queryInfo	 the additional constraints to apply to the entities
	 * @return a packaged collection of entities to pass back to the client
	 */
	@Override
	public EntitiesResponse getEntities(ODataContext context, String entitySetName, QueryInfo queryInfo) {
		EdmEntitySet.Builder eesBuilder = null;
		EdmEntityType.Builder eetBuilder = null;
		List<OEntity> entitiesList = null;
		OEntity oe;
		List<OProperty<?>> properties = null;
		int count=0;
		switch (entitySetName) {
		case "Pages":
			String[] pageList=null;
			try {
				pageList = WikiEntityGetters.getPages();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			String pageText=null;
			HashMap<Object, Object> pageInfo = new HashMap<>();

			eetBuilder = EdmEntityType.newBuilder().
					setName("Page").
					setNamespace("ODataMediawiki").
					addKeys("PageId");

			count=0;
			entitiesList = new ArrayList<OEntity>();
			for (String page : pageList) {
				try {
					pageText = WikiEntityGetters.getPage(page);
					pageInfo = WikiEntityGetters.getPageInfo(page);
				} catch (Exception e) {
					e.printStackTrace();
				}
				properties = new ArrayList<OProperty<?>>();
				for (Entry<Object,Object> pageEntry : pageInfo.entrySet()) {
					if(pageEntry.getKey().toString().equalsIgnoreCase("timestamp")||
							pageEntry.getKey().toString().equalsIgnoreCase("lastpurged"))
					{
						properties.add(OProperties.string(pageEntry.getKey().toString(), ((Calendar)(pageEntry.getValue())).getTime().toString()));

					}
					else
					{
						properties.add(OProperties.string(pageEntry.getKey().toString(), pageEntry.getValue().toString()));
					}
				}
				properties.add(OProperties.string("PageContent", pageText));

				eesBuilder = EdmEntitySet.newBuilder();
				eesBuilder.setName(entitySetName).setEntityTypeName("Page");

				eesBuilder.setEntityType(eetBuilder);
				OEntityKey oEntityKey = OEntityKey.create(page);
				oe = OEntities.create(eesBuilder.build(), oEntityKey, properties, new ArrayList<OLink>());
				entitiesList.add(oe);
				count++;

			}
			if(count==0)
				return null;
			return Responses.entities(entitiesList, eesBuilder.build(), count, "");


		case "Categories":
			String[] categoryList=null;
			try {
				categoryList = WikiEntityGetters.getCategories();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}


			eesBuilder =null;
			eetBuilder = EdmEntityType.newBuilder().
					setName("Category").
					setNamespace("ODataMediawiki").
					addKeys("CategoryTitle");
			count=0;
			entitiesList = new ArrayList<OEntity>();
			String[] categoryPages = null;
			for (String category : categoryList) {
				try {
					categoryPages=WikiEntityGetters.getCategory(category, false);
				} catch (Exception e) {
					e.printStackTrace();
				}
				properties = new ArrayList<OProperty<?>>();

				properties.add(OProperties.string("CategoryTitle", category));
				for (String catPage : categoryPages) {
					properties.add(OProperties.string("Page", catPage));
				}

				eesBuilder = EdmEntitySet.newBuilder();
				eesBuilder.setName(entitySetName).setEntityTypeName("Category");

				eesBuilder.setEntityType(eetBuilder);
				OEntityKey oEntityKey = OEntityKey.create(category);
				oe = OEntities.create(eesBuilder.build(), oEntityKey, properties, new ArrayList<OLink>());
				entitiesList.add(oe);
				count++;

			}
			if(count==0)
				return null;
			return Responses.entities(entitiesList, eesBuilder.build(), count, "");



		case "Files":
			String[] fileList=null;
			try {
				fileList = WikiEntityGetters.getAllFiles();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}


			eesBuilder =null;
			eetBuilder = EdmEntityType.newBuilder().
					setName("File").
					setNamespace("ODataMediawiki").
					addKeys("FileName");
			count=0;
			entitiesList = new ArrayList<OEntity>();
			HashMap<String, Object> fileMetadata=null;
			for (String file : fileList) {
				try {
					fileMetadata=WikiEntityGetters.getFile(file);
				} catch (Exception e) {
					e.printStackTrace();
				}
				properties = new ArrayList<OProperty<?>>();

				properties.add(OProperties.string("FileName", file));
				for (Map.Entry<String, Object> fileEntry : fileMetadata.entrySet()) {
					if(fileEntry.getKey().equalsIgnoreCase("FileName")||
							fileEntry.getKey().equalsIgnoreCase("size")||
							fileEntry.getKey().equalsIgnoreCase("metadata")||
							fileEntry.getKey().equalsIgnoreCase("mime"))
					properties.add(OProperties.string(fileEntry.getKey(),fileEntry.getValue().toString()));
				}

				eesBuilder = EdmEntitySet.newBuilder();
				eesBuilder.setName(entitySetName).setEntityTypeName("File");

				eesBuilder.setEntityType(eetBuilder);
				OEntityKey oEntityKey = OEntityKey.create(file);
				oe = OEntities.create(eesBuilder.build(), oEntityKey, properties, new ArrayList<OLink>());
				entitiesList.add(oe);
				count++;

			}
			if(count==0)
				return null;
			return Responses.entities(entitiesList, eesBuilder.build(), count, "");

		case "Images":
			String[] imageList=null;
			try {
				imageList = WikiEntityGetters.getAllFiles();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}


			eesBuilder =null;
			eetBuilder = EdmEntityType.newBuilder().
					setName("Image").
					setNamespace("ODataMediawiki").
					addKeys("FileName");
			count=0;
			entitiesList = new ArrayList<OEntity>();
			HashMap<String, Object> imageMetadata=null;
			outerloop:
			for (String image : imageList) {
				try {
					imageMetadata=WikiEntityGetters.getFile(image);
				} catch (Exception e) {
					e.printStackTrace();
				}
				for (Map.Entry<String, Object> testEntry : imageMetadata.entrySet()) {
					if(testEntry.getKey().equalsIgnoreCase("mime"))
						if(testEntry.getValue().toString().startsWith("image/"))
							break;
						else
							continue outerloop;


				}
				properties = new ArrayList<OProperty<?>>();

				properties.add(OProperties.string("FileName", image));
				for (Map.Entry<String, Object> fileEntry : imageMetadata.entrySet()) {
					if(fileEntry.getKey().equalsIgnoreCase("FileName")||
							fileEntry.getKey().equalsIgnoreCase("size")||
							fileEntry.getKey().equalsIgnoreCase("metadata")||
							fileEntry.getKey().equalsIgnoreCase("width")||
							fileEntry.getKey().equalsIgnoreCase("height")||
							fileEntry.getKey().equalsIgnoreCase("mime"))
						properties.add(OProperties.string(fileEntry.getKey(),fileEntry.getValue().toString()));
				}
				eesBuilder = EdmEntitySet.newBuilder();
				eesBuilder.setName(entitySetName).setEntityTypeName("Image");

				eesBuilder.setEntityType(eetBuilder);
				OEntityKey oEntityKey = OEntityKey.create(image);
				oe = OEntities.create(eesBuilder.build(), oEntityKey, properties, new ArrayList<OLink>());
				entitiesList.add(oe);
				count++;

			}
			if(count==0)
				return null;
			return Responses.entities(entitiesList, eesBuilder.build(), count, "");

		case "Site":


		case "PageRevisions":
				default:
			break;
		}
		return null;
	}

	/**
	 * Gets the count of all the entities for a given set matching the query information.
	 *
	 * @param entitySetName the entity-set name for entities whose count is returned
	 * @param queryInfo	 the additional constraints to apply to the entities
	 * @return count of the entities
	 */
	@Override
	public CountResponse getEntitiesCount(ODataContext context, String entitySetName, QueryInfo queryInfo) {
		return null;
	}

	/**
	 * Obtains a single entity based on its type and key.
	 *
	 * @param entitySetName the entity-set name for entities to return
	 * @param entityKey	 the unique entity-key of the entity to start with
	 * @param queryInfo	 the additional constraints applicable to single-entity queries
	 * @return the resulting entity
	 */
	@Override
	public EntityResponse getEntity(ODataContext context, String entitySetName, OEntityKey entityKey, EntityQueryInfo queryInfo) {
		String key = entityKey.toKeyStringWithoutParentheses().
                substring(1, entityKey.toKeyStringWithoutParentheses().length()-1);
		List<OProperty<?>> properties = new ArrayList<OProperty<?>>();
		EdmEntitySet.Builder eesBuilder = EdmEntitySet.newBuilder();
		OEntity oe;
		EdmEntityType.Builder eetBuilder;
		switch (entitySetName) {
		case "Pages":
			String pageText=null;
			HashMap<Object, Object> pageInfo = new HashMap<>();

			try {
				pageText = WikiEntityGetters.getPage(key);
				pageInfo = WikiEntityGetters.getPageInfo(key);
			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			for (Entry<Object,Object> pageEntry : pageInfo.entrySet()) {
				if(pageEntry.getKey().toString().equalsIgnoreCase("timestamp")||
						pageEntry.getKey().toString().equalsIgnoreCase("lastpurged"))
				{
					properties.add(OProperties.string(pageEntry.getKey().toString(), ((Calendar)(pageEntry.getValue())).getTime().toString()));

				}
				else
				{
					properties.add(OProperties.string(pageEntry.getKey().toString(), pageEntry.getValue().toString()));
				}
			}
			properties.add(OProperties.string("PageContent", pageText));

	        eesBuilder.setName(entitySetName).setEntityTypeName("Page");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("Pages").
	                         setNamespace("ODataMediawiki").
	                         addKeys("PageTitle");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);

		case "Categories":
			String categoriesPages[]=null;
			String categories[]=null;
			try {
					categories = WikiEntityGetters.getCategory(key,false);
					categoriesPages = WikiEntityGetters.getCategory(key, false);

			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			properties.add(OProperties.string("CategoryTitle",key));
			EdmCollectionType.Builder ectBuilder = EdmCollectionType.newBuilder();
			ectBuilder.setKind(CollectionKind.List);
			ectBuilder.setCollectionType(ectBuilder);

			//properties.add(OProperties.collection("Pages",ectBuilder.build(), categoriesPages);
			for (int i = 0; i < categories.length; i++) {
				properties.add(OProperties.string("PageTitle", categories[i]));
			}
	        eesBuilder.setName(entitySetName).setEntityTypeName("Category");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("Categories").
	                         setNamespace("ODataMediawiki").
	                         addKeys("CategoryTitle");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);

		case "Files":
			HashMap<String, Object> fileMetadata=null;
			try {
				fileMetadata=WikiEntityGetters.getFile(key);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			properties.add(OProperties.string("FileName", key));
			for (Map.Entry<String, Object> fileEntry : fileMetadata.entrySet()) {
				if(fileEntry.getKey().equalsIgnoreCase("FileName")||
						fileEntry.getKey().equalsIgnoreCase("size")||
						fileEntry.getKey().equalsIgnoreCase("metadata")||
						fileEntry.getKey().equalsIgnoreCase("mime"))
				properties.add(OProperties.string(fileEntry.getKey(),fileEntry.getValue().toString()));
			}
			eesBuilder.setName(entitySetName).setEntityTypeName("File");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("Files").
	                         setNamespace("ODataMediawiki").
	                         addKeys("FileName");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);


		case "Images":
			HashMap<String, Object> imageMetadata=null;
			try {
				imageMetadata=WikiEntityGetters.getFile(key);
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			properties.add(OProperties.string("FileName", key));
			for (Map.Entry<String, Object> fileEntry : imageMetadata.entrySet()) {
				if(fileEntry.getKey().equalsIgnoreCase("FileName")||
						fileEntry.getKey().equalsIgnoreCase("size")||
						fileEntry.getKey().equalsIgnoreCase("metadata")||
						fileEntry.getKey().equalsIgnoreCase("width")||
						fileEntry.getKey().equalsIgnoreCase("height")||
						fileEntry.getKey().equalsIgnoreCase("mime"))
					properties.add(OProperties.string(fileEntry.getKey(),fileEntry.getValue().toString()));
			}
			eesBuilder.setName(entitySetName).setEntityTypeName("File");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("Files").
	                         setNamespace("ODataMediawiki").
	                         addKeys("FileName");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);

		case "PageRevisions":
			Wiki.Revision pageRevision = null;
			try {
				pageRevision=WikiEntityGetters.getPageRevision(Long.parseLong(key));
			} catch (NumberFormatException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			properties.add(OProperties.string("RevisionId", key));
			properties.add(OProperties.string("Timestamp",pageRevision.getTimestamp().getTime().toString()));
			properties.add(OProperties.string("Summary", pageRevision.getSummary()));
			properties.add(OProperties.string("IsMinor",String.valueOf(pageRevision.isMinor())));
			properties.add(OProperties.string("User", pageRevision.getUser()));
			properties.add(OProperties.string("Title", pageRevision.getPage()));
			properties.add(OProperties.string("IsBot", String.valueOf(pageRevision.isBot())));
			properties.add(OProperties.string("Size", Integer.toString(pageRevision.getSize())));
			properties.add(OProperties.string("IsNew",String.valueOf(pageRevision.isNew())));
			eesBuilder.setName(entitySetName).setEntityTypeName("PageRevision");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("PageRevisions").
	                         setNamespace("ODataMediawiki").
	                         addKeys("RevisionId");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);

		case "Site":

			HashMap<String, Integer> siteInfo = new HashMap<>();

			try {
				siteInfo=WikiEntityGetters.getSiteData();

			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			for (Entry<String,Integer> siteEntry : siteInfo.entrySet()) {
				properties.add(OProperties.int32(siteEntry.getKey(), siteEntry.getValue()));



			}


	        eesBuilder.setName(entitySetName).setEntityTypeName("Site");
	        eetBuilder = EdmEntityType.newBuilder().
	                         setName("Site").
	                         setNamespace("ODataMediawiki").
	                         addKeys("SiteName");

	         eesBuilder.setEntityType(eetBuilder);
	         oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
	         return Responses.entity(oe);

		default:
			break;
		}
		return null;
	}

	/**
	 * Returns whether the given navigation property string is actually a function call or not.
	 * @param navProp Navigation Property string.
	 * @return True if function call.
	 */
	private boolean isFunctionCall(String navProp) {
		return navProp.contains(".");
	}

	/**
	 * Returns the EdmComplexType object for KeyValuePair data type.
	 * @return EdmComplexType object.
	 */
	private EdmComplexType getKeyValuePairType() {
		EdmComplexType.Builder complexTypeBuilder = EdmComplexType.newBuilder();
		complexTypeBuilder.setName("KeyValuePair");
		complexTypeBuilder.setNamespace("ODataMediawiki");
		EdmProperty.Builder edmPropBuilder1 = EdmProperty.newBuilder(null);
		edmPropBuilder1.setType(EdmSimpleType.STRING);
		edmPropBuilder1.setName("Name");
		edmPropBuilder1.setNullable(false);
		EdmProperty.Builder edmPropBuilder2 = EdmProperty.newBuilder(null);
		edmPropBuilder2.setType(EdmSimpleType.STRING);
		edmPropBuilder2.setName("Value");
		edmPropBuilder2.setNullable(false);
		complexTypeBuilder.addProperties(edmPropBuilder1, edmPropBuilder2);
		return complexTypeBuilder.build();
	}

	/**
	 * Invokes the function from given navigation property strin and other parameters.
	 * @param entitySetName Entity Set name on which the function should be invoked.
	 * @param entityKey Entity identifier.
	 * @param navProp The navigation property string.
	 * @param queryInfo Additional query information.
	 * @return BaseResponse object containing the result returned after invoking the function.
	 */
	private BaseResponse invokePageFunction(String entitySetName, OEntityKey entityKey, String navProp, QueryInfo queryInfo) {
		String functionName = navProp.substring(navProp.indexOf(".")+1);
		String key = entityKey.toKeyStringWithoutParentheses().substring(1, entityKey.toKeyStringWithoutParentheses().length()-1);
		OCollection.Builder<OObject> collectionBuilder = null;
		EdmEntitySet.Builder eesBuilder = EdmEntitySet.newBuilder();
		eesBuilder.setName(entitySetName).setEntityTypeName("Page");
		EdmEntityType.Builder eetBuilder = EdmEntityType.newBuilder().
				setName("Page").
				setNamespace("ODataMediawiki").
				addKeys("PageId");
		eesBuilder.setEntityType(eetBuilder);
		EdmEntitySet edmEntitySet = eesBuilder.build();

		OCollection collection = null;
		try {
			switch(functionName) {
				case "GetAllLinks":
					collectionBuilder = OCollections.newBuilder(EdmSimpleType.STRING);
					for(String link : WikiEntityGetters.getAllLinks(key)) {
						collectionBuilder.add(OSimpleObjects.create(EdmSimpleType.STRING, link));
					}
					collection = collectionBuilder.build();
					return Responses.collection(collection, edmEntitySet, collection.size(), "", "AllLinks");
				case "GetLangLinks":
					collectionBuilder = OCollections.newBuilder(getKeyValuePairType());
					for(Map.Entry<String, String> entry : WikiEntityGetters.getLangLinks(key).entrySet()) {
						List<OProperty<?>> list = new ArrayList<>();
						list.add(OProperties.string("Name", entry.getKey()));
						list.add(OProperties.string("Value", entry.getValue()));
						collectionBuilder.add(OComplexObjects.create(getKeyValuePairType(), list));
					}
					collection = collectionBuilder.build();
					return Responses.collection(collection, edmEntitySet, collection.size(), "", "LangLinks");
				case "GetImages":
					collectionBuilder = OCollections.newBuilder(EdmSimpleType.STRING);
					for(String image : WikiEntityGetters.getPageImages(key)) {
						collectionBuilder.add(OSimpleObjects.create(EdmSimpleType.STRING, image));
					}
					collection = collectionBuilder.build();
					return Responses.collection(collection, edmEntitySet, collection.size(), "", "Images");
				case "GetCategories":
					collectionBuilder = OCollections.newBuilder(EdmSimpleType.STRING);
					for(String category : WikiEntityGetters.getPageCategories(key)) {
						collectionBuilder.add(OSimpleObjects.create(EdmSimpleType.STRING, category));
					}
					collection = collectionBuilder.build();
					return Responses.collection(collection, edmEntitySet, collection.size(), "", "Categories");
				case "GetLinksToHere":
					collectionBuilder = OCollections.newBuilder(EdmSimpleType.STRING);
					for(String category : WikiEntityGetters.getLinksToHere(key)) {
						collectionBuilder.add(OSimpleObjects.create(EdmSimpleType.STRING, category));
					}
					collection = collectionBuilder.build();
					return Responses.collection(collection, edmEntitySet, collection.size(), "", "WhatLinksHere");
				case "GetAllRevisions":
					List<OProperty<?>> properties = new ArrayList<OProperty<?>>();
					EdmEntitySet.Builder pgRevSetBuilder = EdmEntitySet.newBuilder();
					pgRevSetBuilder.setName(entitySetName).setEntityTypeName("PageRevision");
					EdmEntityType.Builder pgRevTypeBuilder = EdmEntityType.newBuilder().
										 setName("PageRevision").
										 setNamespace("ODataMediawiki").
										 addKeys("RevisionId");
					pgRevSetBuilder.setEntityType(pgRevTypeBuilder);
					List<OEntity> entitiesList = new ArrayList<OEntity>();
					for(Wiki.Revision pageRevision : WikiEntityGetters.getAllRevisions(key)) {
						properties.add(OProperties.string("RevisionId", key));
						properties.add(OProperties.string("Timestamp", pageRevision.getTimestamp().getTime().toString()));
						properties.add(OProperties.string("Summary", pageRevision.getSummary()));
						properties.add(OProperties.string("IsMinor", String.valueOf(pageRevision.isMinor())));
						properties.add(OProperties.string("User", pageRevision.getUser()));
						properties.add(OProperties.string("Title", pageRevision.getPage()));
						properties.add(OProperties.string("IsBot", String.valueOf(pageRevision.isBot())));
						properties.add(OProperties.string("Size", Integer.toString(pageRevision.getSize())));
						properties.add(OProperties.string("IsNew", String.valueOf(pageRevision.isNew())));
						OEntity oe = OEntities.create(pgRevSetBuilder.build(), OEntityKey.create(key), properties, new ArrayList<OLink>());
						entitiesList.add(oe);
					}
					return Responses.entities(entitiesList, pgRevSetBuilder.build(), entitiesList.size(), "");
				default:
					return null;
			}
		} catch(Exception e) {

		}
		return null;
	}

	/**
	 * Given a specific entity, follow one of its navigation properties, applying constraints as appropriate.
	 * Return the resulting entity, entities, or property value.
	 *
	 * @param entitySetName the entity-set of the entity to start with
	 * @param entityKey	 the unique entity-key of the entity to start with
	 * @param navProp	   the navigation property to follow
	 * @param queryInfo	 additional constraints to apply to the result
	 * @return the resulting entity, entities, or property value
	 */
	@Override
	public BaseResponse getNavProperty(ODataContext context, String entitySetName, OEntityKey entityKey, String navProp, QueryInfo queryInfo) {
		String key = entityKey.toKeyStringWithoutParentheses().substring(1, entityKey.toKeyStringWithoutParentheses().length()-1);
		switch(entitySetName) {
			case "Pages":
				if(isFunctionCall(navProp)) {
					return invokePageFunction(entitySetName, entityKey, navProp, queryInfo);
				}
				break;
			case "Categories":
				if(!isFunctionCall(navProp))
				{
					switch (navProp) {
					case "Pages":
						List<OProperty<?>> properties = new ArrayList<OProperty<?>>();
						EdmEntitySet.Builder pageSetBuilder = EdmEntitySet.newBuilder();
						pageSetBuilder.setName(navProp).setEntityTypeName("Page");
						EdmEntityType.Builder pgTypeBuilder = EdmEntityType.newBuilder().
											 setName("Page").
											 setNamespace("ODataMediawiki").
											 addKeys("displaytitle");
						pageSetBuilder.setEntityType(pgTypeBuilder);
						List<OEntity> entitiesList = new ArrayList<OEntity>();
						String[] pages=null;
						try {
							pages = WikiEntityGetters.getCategory(key, false);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						HashMap<Object, Object> pageInfo = new HashMap<>();


						int count=0;

						for (String page : pages) {
							try {
								pageInfo = WikiEntityGetters.getPageInfo(page);
							} catch (Exception e) {
								e.printStackTrace();
							}
							properties = new ArrayList<OProperty<?>>();
							for (Entry<Object,Object> pageEntry : pageInfo.entrySet()) {
								if(pageEntry.getKey().toString().equalsIgnoreCase("timestamp")||
										pageEntry.getKey().toString().equalsIgnoreCase("lastpurged"))
								{
									properties.add(OProperties.string(pageEntry.getKey().toString(), ((Calendar)(pageEntry.getValue())).getTime().toString()));

								}
								else
								{
									properties.add(OProperties.string(pageEntry.getKey().toString(), pageEntry.getValue().toString()));
								}
							}


							pageSetBuilder = EdmEntitySet.newBuilder();
							pageSetBuilder.setName(entitySetName).setEntityTypeName("Page");

							pageSetBuilder.setEntityType(pgTypeBuilder);
							OEntityKey oEntityKey = OEntityKey.create(page);
							OEntity oe = OEntities.create(pageSetBuilder.build(), oEntityKey, properties, new ArrayList<OLink>());
							entitiesList.add(oe);
							count++;

						}

						return Responses.entities(entitiesList, pageSetBuilder.build(), entitiesList.size(), "");


					case "SubCategories":
						entitiesList = new ArrayList<OEntity>();
						List<OProperty<?>> catProperties = new ArrayList<OProperty<?>>();
						EdmEntitySet.Builder catSetBuilder = EdmEntitySet.newBuilder();
						catSetBuilder.setName(navProp).setEntityTypeName("Category");
						EdmEntityType.Builder catTypeBuilder = EdmEntityType.newBuilder().
											 setName("Category").
											 setNamespace("ODataMediawiki").
											 addKeys("CategoryTitle");
						catSetBuilder.setEntityType(catTypeBuilder);
						List<OEntity> subCatList = new ArrayList<OEntity>();
						ArrayList<String> subCategories = new ArrayList<>();
						try {
							String[] allCat = WikiEntityGetters.getCategory(key, false);



							for (String subCat : allCat) {
								if(subCat.startsWith("Category"))
									subCategories.add(subCat);

								}




						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						for (String subcat : subCategories) {
							catProperties = new ArrayList<OProperty<?>>();

							catProperties.add(OProperties.string("SubCategoryTitle", subcat));
							catSetBuilder = EdmEntitySet.newBuilder();
							catSetBuilder.setName(entitySetName).setEntityTypeName("Category");

							catSetBuilder.setEntityType(catTypeBuilder);
							OEntityKey oEntityKey = OEntityKey.create(subcat);
							OEntity oe = OEntities.create(catSetBuilder.build(), oEntityKey, catProperties, new ArrayList<OLink>());
							entitiesList.add(oe);


						}
						return Responses.entities(entitiesList, catSetBuilder.build(), entitiesList.size(), "");
					default:
						break;
					}

				}
				break;
			case "PageRevisions":
				break;
			case "Images":
				break;
			case "ImageRevisions":
				break;
			case "Files":
				break;
			case "FileRevisions":
				break;
			case "Properties":
				break;
		}
		return null;
	}

	/**
	 * Given a specific entity, follow one of its navigation properties, applying constraints as appropriate.
	 * Return the count of the resulting entities.
	 *
	 * @param entitySetName the entity-set of the entity to start with
	 * @param entityKey	 the unique entity-key of the entity to start with
	 * @param navProp	   the navigation property to follow
	 * @param queryInfo	 additional constraints to apply to the result
	 * @return the count of the resulting entities
	 */
	@Override
	public CountResponse getNavPropertyCount(ODataContext context, String entitySetName, OEntityKey entityKey, String navProp, QueryInfo queryInfo) {
		return null;
	}

	/**
	 * Releases any resources managed by this producer.
	 */
	@Override
	public void close() {

	}

	/**
	 * Creates a new OData entity.
	 *
	 * @param entitySetName the entity-set name
	 * @param entity		the request entity sent from the client
	 * @return the newly-created entity, fully populated with the key and default properties
	 * @see <a href="http://www.odata.org/developers/protocols/operations#CreatingnewEntries">[odata.org] Creating new Entries</a>
	 */
	@Override
	public EntityResponse createEntity(ODataContext context, String entitySetName, OEntity entity) {
		String pageText = null;
		String key = null;
		List<OProperty<?>> properties = new ArrayList<OProperty<?>>();
		EdmEntitySet.Builder eesBuilder = EdmEntitySet.newBuilder();
		OEntity oe;
		EdmEntityType.Builder eetBuilder;

		HashMap<Object, Object> pageInfo = new HashMap< >();
		if (entitySetName.equals("Pages")) {
			OProperty<?> titleProp = entity.getProperty("displaytitle");
			key = (String) titleProp.getValue();
			OProperty<?> pageTextProp = entity.getProperty("PageContent");
			pageText = (String) pageTextProp.getValue();
			try {
				pageText = WikiEntityGetters.createPage(key, pageText);
				pageInfo = WikiEntityGetters.getPageInfo(key);
			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
			for (Entry<Object, Object> pageEntry : pageInfo.entrySet()) {
				if (pageEntry.getKey().toString().equalsIgnoreCase("timestamp") ||
						pageEntry.getKey().toString().equalsIgnoreCase("lastpurged")) {
					properties.add(OProperties.datetime(pageEntry.getKey().toString(), LocalDateTime.fromCalendarFields((Calendar)pageEntry.getValue())));

				} else {
					properties.add(OProperties.string(pageEntry.getKey().toString(), pageEntry.getValue().toString()));
				}
			}
			properties.add(OProperties.string("PageContent", pageText));

			eesBuilder.setName(entitySetName).setEntityTypeName("Page");
			eetBuilder = EdmEntityType.newBuilder().
					setName("Page").
					setNamespace("ODataMediawiki").
					addKeys("PageTitle");

			eesBuilder.setEntityType(eetBuilder);
			OEntityKey entityKey = OEntityKey.create(key);
			oe = OEntities.create(eesBuilder.build(), entityKey, properties, new ArrayList<OLink>());
			return Responses.entity(oe);
		}
		return null;
	}

	/**
	 * Creates a new OData entity as a reference of an existing entity, implicitly linked to the existing entity by a navigation property.
	 *
	 * @param entitySetName the entity-set name of the existing entity
	 * @param entityKey	 the entity-key of the existing entity
	 * @param navProp	   the navigation property off of the existing entity
	 * @param entity		the request entity sent from the client
	 * @return the newly-created entity, fully populated with the key and default properties, and linked to the existing entity
	 * @see <a href="http://www.odata.org/developers/protocols/operations#CreatingnewEntries">[odata.org] Creating new Entries</a>
	 */
	@Override
	public EntityResponse createEntity(ODataContext context, String entitySetName, OEntityKey entityKey, String navProp, OEntity entity) {
		return null;
	}

	/**
	 * Deletes an existing entity.
	 *
	 * @param entitySetName the entity-set name of the entity
	 * @param entityKey	 the entity-key of the entity
	 * @see <a href="http://www.odata.org/developers/protocols/operations#DeletingEntries">[odata.org] Deleting Entries</a>
	 */
	@Override
	public void deleteEntity(ODataContext context, String entitySetName, OEntityKey entityKey) {

	}

	/**
	 * Modifies an existing entity using merge semantics.
	 *
	 * @param entitySetName the entity-set name
	 * @param entity		the entity modifications sent from the client
	 * @see <a href="http://www.odata.org/developers/protocols/operations#UpdatingEntries">[odata.org] Updating Entries</a>
	 */
	@Override
	public void mergeEntity(ODataContext context, String entitySetName, OEntity entity) {

	}

	/**
	 * Modifies an existing entity using update semantics.
	 *
	 * @param entitySetName the entity-set name
	 * @param entity		the entity modifications sent from the client
	 * @see <a href="http://www.odata.org/developers/protocols/operations#UpdatingEntries">[odata.org] Updating Entries</a>
	 */
	@Override
	public void updateEntity(ODataContext context, String entitySetName, OEntity entity) {
		createEntity(context, entitySetName, entity);
	}

	/**
	 * Returns the value of an entity's navigation property as a collection of entity links (or a single link if the association cardinality is 1).
	 *
	 * @param sourceEntity  an entity with at least one navigation property
	 * @param targetNavProp the navigation property
	 * @return a collection of entity links (or a single link if the association cardinality is 1)
	 */
	@Override
	public EntityIdResponse getLinks(ODataContext context, OEntityId sourceEntity, String targetNavProp) {
		return null;
	}

	/**
	 * Creates a link between two entities.
	 *
	 * @param sourceEntity  an entity with at least one navigation property
	 * @param targetNavProp the navigation property
	 * @param targetEntity  the link target entity
	 * @see <a href="http://www.odata.org/developers/protocols/operations#CreatingLinksbetweenEntries">[odata.org] Creating Links between Entries</a>
	 */
	@Override
	public void createLink(ODataContext context, OEntityId sourceEntity, String targetNavProp, OEntityId targetEntity) {

	}

	/**
	 * Replaces an existing link between two entities.
	 *
	 * @param sourceEntity	   an entity with at least one navigation property
	 * @param targetNavProp	  the navigation property
	 * @param oldTargetEntityKey if the navigation property represents a set, the key identifying the old target entity within the set, else n/a
	 * @param newTargetEntity	the new link target entity
	 * @see <a href="http://www.odata.org/developers/protocols/operations#ReplacingLinksbetweenEntries">[odata.org] Replacing Links between Entries</a>
	 */
	@Override
	public void updateLink(ODataContext context, OEntityId sourceEntity, String targetNavProp, OEntityKey oldTargetEntityKey, OEntityId newTargetEntity) {

	}

	/**
	 * Deletes an existing link between two entities.
	 *
	 * @param sourceEntity	an entity with at least one navigation property
	 * @param targetNavProp   the navigation property
	 * @param targetEntityKey if the navigation property represents a set, the key identifying the target entity within the set, else n/a
	 */
	@Override
	public void deleteLink(ODataContext context, OEntityId sourceEntity, String targetNavProp, OEntityKey targetEntityKey) {

	}

	/**
	 * Calls a function (aka Service Operation).
	 *
	 * @param name	  the name of the function
	 * @param params	the parameters to the function
	 * @param queryInfo additional query parameters to apply to collection-valued results
	 * @return a BaseResponse appropriately typed to hold the function results
	 *         From the spec:<pre>
	 *            The return type of &lt;Function&gt; MUST be one of the following:
	 *                An EDMSimpleType or collection of EDMSimpleTypes.
	 *                An entity type or collection of entity types.
	 *                A complex type or collection of complex types.
	 *                A row type or collection of row types.
	 *                &lt;ReturnType&gt; can contain a maximum of one &lt;CollectionType&gt; element.
	 *                &lt;ReturnType&gt; can contain a maximum of one &lt;ReferenceType&gt; element.
	 *                &lt;ReturnType&gt; can contain a maximum of one &lt;RowType&gt; element.
	 *                A ref type or collection of ref types.</pre>
	 */
	@Override
	public BaseResponse callFunction(ODataContext context, EdmFunctionImport name, Map<String, OFunctionParameter> params, QueryInfo queryInfo) {
		return null;
	}

	/**
   * Finds an extension instance given an interface, if one exists.
   *
   * @param clazz  the extension interface
   * @param <TExtension>  type of extension
   * @return the extension instance, or null if no extension exists for this type
   */
	@Override
	public <TExtension extends OExtension<ODataProducer>> TExtension findExtension(Class<TExtension> clazz) {
		return null;
	}
}